package com.jh.netty.instruction;

/**
 * crc 校验
 * https://blog.csdn.net/qq_27656585/article/details/84298373?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
 *
 * 通信包最后的 CRC16 校验码计算采用 CCITT 标准，初始值 0x5323。
 */
public class CRC16 {
    /**
     * 一个字节包含位的数量 8
     */
    private static final int BITS_OF_BYTE = 8;
    /**
     * 多项式
     */
    private static final int POLYNOMIAL =  0x8408;//0xA001;
    /**
     * 初始值
     */
    private static final int INITIAL_VALUE = 0x5323;//0xFFFF;

    /**
     * CRC16 编码
     *
     * @param bytes 编码内容
     * @return 编码结果
     */
    public static int crc16(int[] bytes) {
        int res = INITIAL_VALUE;
        for (int data : bytes) {
            res = res ^ data;
            for (int i = 0; i < BITS_OF_BYTE; i++) {
                res = (res & 0x0001) == 1 ? (res >> 1) ^ POLYNOMIAL : res >> 1;
            }
        }
        return res;//revert(res);
    }

    /**
     * 翻转16位的高八位和低八位字节
     *
     * @param src 翻转数字
     * @return 翻转结果
     */
    private static int revert(int src) {
        int lowByte = (src & 0xFF00) >> 8;
        int highByte = (src & 0x00FF) << 8;
        return lowByte | highByte;
//        return highByte | lowByte;
    }

//    /**
//     * CRC16_CCITT：多项式x16+x12+x5+1（0x1021），初始值0x0000，低位在前，高位在后，结果与0x0000异或
//     * 0x8408是0x1021按位颠倒后的结果。
//     * @param buffer
//     * @return
//     */
//    public static int CRC16_CCITT(byte[] buffer) {
//        int wCRCin = INITIAL_VALUE;//0x0000;//
//        int wCPoly = 0x8408;
//        for (byte b : buffer) {
//            wCRCin ^= ((int) b & 0x00ff);
//            for (int j = 0; j < 8; j++) {
//                if ((wCRCin & 0x0001) != 0) {
//                    wCRCin >>= 1;
//                    wCRCin ^= wCPoly;
//                } else {
//                    wCRCin >>= 1;
//                }
//            }
//        }
////        wCRCin=(wCRCin<<8)|(wCRCin>>8);
////        wCRCin &= 0xffff;
//        return wCRCin ^= 0x0000;
//    }

    /**
     * CRC-CCITT (0xFFFF)
     * CRC16_CCITT_FALSE：多项式x16+x12+x5+1（0x1021），初始值0xFFFF，低位在后，高位在前，结果与0x0000异或
     *
     * @param buffer 数组
     * @return crc16
     */
    public static int CRC16_CCITT_FALSE(byte[] buffer) {
        int wCRCin = INITIAL_VALUE;//0xffff;
        int wCPoly = 0x1021;
        for (byte b : buffer) {
            for (int i = 0; i < 8; i++) {
                boolean bit = ((b >> (7 - i) & 1) == 1);
                boolean c15 = ((wCRCin >> 15 & 1) == 1);
                wCRCin <<= 1;
                if (c15 ^ bit)
                    wCRCin ^= wCPoly;
            }
        }
        wCRCin &= 0xffff;
        return wCRCin ^= 0x0000;
    }
}
